﻿using SlamDunk.MES.DataDrive.Common.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace SlamDunk.MES.DataDrive.Common
{
    /// <summary>
    /// 反射帮助类
    /// </summary>
    public static class ReflectionHelper
    {
        //1、获取一个dll中的某种特性标记的类
        //2、获取类中的某种特性标记的方法
        //3、通过反射执行方法

        #region # 根据程序集名称获取数据驱动菜单集合——List<DataMenu> GetDataMenus(string assemblyName)
        /// <summary>
        /// 根据程序集名称获取数据驱动菜单集合
        /// </summary>
        /// <param name="assemblyName">程序集名称</param>
        /// <returns></returns>
        public static List<DataMenu> GetDataMenus(string assemblyName)
        {
            Assembly assembly = Assembly.Load(assemblyName);//程序集名.dll
            //获取程序集中所有类
            List<TypeInfo> typeInfos = assembly.DefinedTypes.ToList();
            //筛选出特定特性的类
            var dataTagTypeInfos = typeInfos.Where(x => x.CustomAttributes.Any(v => v.AttributeType == typeof(DataTagAttribute)));
            List<DataMenu> dataMenus = new List<DataMenu>();
            foreach (TypeInfo dataTagTypeInfo in dataTagTypeInfos)
            {
                //获取类中特定特性的方法
                List<MethodInfo> methodInfos = dataTagTypeInfo.GetMethods().Where(x => x.CustomAttributes.Any(v => v.AttributeType == typeof(DataTagAttribute))).ToList();
                foreach (MethodInfo methodInfo in methodInfos)
                {
                    var methodAttribute = methodInfo.GetCustomAttribute<DataTagAttribute>();
                    var typeAttribute = dataTagTypeInfo.GetCustomAttribute<DataTagAttribute>();
                    methodAttribute.Sort = typeAttribute.Sort * 100 + methodInfos.IndexOf(methodInfo) + 1;//设置方法排序

                    dataMenus.Add(new DataMenu(dataTagTypeInfo, methodInfo, methodAttribute));
                }
            }

            return dataMenus;
        }
        #endregion

        private static Dictionary<TypeInfo, object> typeObjects = new Dictionary<TypeInfo, object>();
        #region # 执行方法——void InvokeMethod(DataMenu dataMenu)
        /// <summary>
        /// 执行方法
        /// </summary>
        /// <param name="dataMenu">数据驱动菜单</param>
        public static void InvokeMethod(DataMenu dataMenu)
        {
            if (ReflectionHelper.typeObjects.All(x => x.Key != dataMenu.TypeInfo))
            {
                ReflectionHelper.typeObjects.Add(dataMenu.TypeInfo, Activator.CreateInstance(dataMenu.TypeInfo));
            }

            var typeObject = ReflectionHelper.typeObjects.First(x => x.Key == dataMenu.TypeInfo);
            dataMenu.MethodInfo.Invoke(typeObject.Value, null);
        }
        #endregion

        #region # 执行特定类型的所有方法——void InvokeMethod(string assemblyName,Type type)
        /// <summary>
        /// 执行特定类型的所有方法
        /// </summary>
        /// <param name="assemblyName">程序集名称</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static void InvokeMethodByInterfaceType(string assemblyName, Type type)
        {
            Assembly assembly = Assembly.Load(assemblyName);//程序集名.dll
            //获取程序集中所有类
            List<TypeInfo> typeInfos = assembly.DefinedTypes.Where(x => x.GetInterfaces().Any(v => v == type)).ToList();
            foreach (TypeInfo typeInfo in typeInfos)
            {
                foreach (MethodInfo typeInfoDeclaredMethod in typeInfo.DeclaredMethods)
                {
                    if (typeInfoDeclaredMethod.IsPublic && typeInfoDeclaredMethod.IsSecurityCritical)
                    {
                        typeInfoDeclaredMethod.Invoke(Activator.CreateInstance(typeInfo), null);
                    }
                }
            }
        }
        #endregion
    }
}
